package com.example.demo.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * 根据 feature 配置动态排除数据库相关的自动配置，避免在未完成数据库配置时启动失败。
 */
public class FeatureToggleEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {

    private static final String PROPERTY_SOURCE_NAME = "featureToggleOverrides";

    private static final String AUTO_CONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

    private static final String[] DATABASE_AUTO_CONFIGS = {
            "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration",
            "org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration",
            "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration",
            "org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration",
            "com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration"
    };

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        boolean databaseEnabled = environment.getProperty("feature.database.enabled", Boolean.class, Boolean.TRUE);
        if (!databaseEnabled) {
            String existing = environment.getProperty(AUTO_CONFIGURE_EXCLUDE, "");
            String merged = mergeExcludes(existing, DATABASE_AUTO_CONFIGS);
            Map<String, Object> map = Map.of(AUTO_CONFIGURE_EXCLUDE, merged);
            environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, map));
        }
    }

    private String mergeExcludes(String existing, String[] additional) {
        Set<String> values = new LinkedHashSet<>();
        if (StringUtils.hasText(existing)) {
            Arrays.stream(existing.split(","))
                    .map(String::trim)
                    .filter(StringUtils::hasText)
                    .forEach(values::add);
        }
        values.addAll(Arrays.asList(additional));
        return String.join(",", values);
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
